﻿#include <stdio.h>
#include "getopt.h"
#include "bb_api.h"
#include <windows.h>

int main(int argc, char** argv)
{
    int c;
    int flag_help = 0;
    int flag_send = 0;
    int sockfd = -1;
    uint32_t port = 0;
    uint32_t delay = 0;
    char buf[8196];
    char pipe_name[MAX_PATH] = {0};
    char* file = NULL;
    FILE* pfile = NULL;
    bb_dev_t* dev = NULL;
    HANDLE handle = INVALID_HANDLE_VALUE;
    int dev_nr = 0;
    bb_host_t* phost = NULL;
    bb_dev_t** devs = NULL;
    bb_dev_handle_t* hdev = NULL;

    while (1) {
        int this_option_optind = optind ? optind : 1;
        int option_index = 0;
        static struct option long_options[] = {
            {"help", no_argument, 0, 'h'},
            {"port", required_argument, 0, 'p'},
            {"delay", required_argument, 0, 'd'},
            {"send_file", required_argument, 0, 'f'},
            {"recv_file", required_argument, 0, 'a'},
            {"send_video", required_argument, 0, 't'},
            {"recv_video", required_argument, 0, 'r'},
            {0, 0, 0, 0}
        };

        c = getopt_long(argc, argv, "hr:t:f:a:p:d:", long_options, &option_index);
        if (c == -1) {
            break;
        }

        switch (c) {
        case 'h':
            flag_help = 1;
            break;
        case 'p':
            port = strtoul(optarg, NULL, 10);
            break;
        case 'd':
            delay = strtoul(optarg, NULL, 10);
            break;
        case 't':
            flag_send = 1;
            sprintf(pipe_name, "\\\\.\\pipe\\%s", optarg);
            break;
        case 'r':
            flag_send = 0;
            sprintf(pipe_name, "\\\\.\\pipe\\%s", optarg);
            break;
        case 'f':
            flag_send = 2;
            file = optarg;
            break;
        case 'a':
            flag_send = -2;
            file = optarg;
            break;
        default:
            printf("?? getopt returned character code 0%o ??\n", c);
            break;
        }
    }

    if (optind < argc) {
        printf("non-option ARGV-elements: ");
        while (optind < argc) {
            printf("%s ", argv[optind++]);
            printf("\n");
        }
    }

    if (flag_help) {
        printf("TDB\n");
        return 0;
    }

    
    // 1. 初始化
    // bb_init();

    // 2. 连接daemon
    if (bb_host_connect(&phost, "127.0.0.1", 50000)) {
        printf("failed to connect host!\n");
        goto quit;
    }

    // 3. 获取设备列表
    if ((dev_nr = bb_dev_getlist(phost, &devs)) <= 0) {
        printf("get dev list failed or no dev!\n");
        goto quit;
    }

    // 4. 打开其中一个
    hdev = bb_dev_open(devs[0]);

    // 5. 释放列表
    bb_dev_freelist(devs);

    if (!hdev) {
        printf("open dev failed!\n");
        goto quit;
    }

    if (flag_send == 1) {
        sockfd = bb_socket_open(hdev, BB_SLOT_0, port, BB_SOCK_FLAG_TX | BB_SOCK_FLAG_RX, NULL);
        if (sockfd < 0) {
            printf("create bb socket failed!\n");
            goto quit;
        }

        handle = ::CreateNamedPipe(pipe_name, PIPE_ACCESS_INBOUND, PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 1024 * 1024, 1024 * 1024, 0, NULL);
        if (handle == INVALID_HANDLE_VALUE) {
            printf("create pipe failed!\n");
            goto quit;
        }

        if (!::ConnectNamedPipe(handle, NULL)) {
            printf("connect pipe failed!\n");
            goto quit;
        }

        while (1) {
            DWORD read = 0;
            if (!::ReadFile(handle, buf, sizeof(buf), &read, NULL)) {
                printf("read pipe failed!\n");
                break;
            }

            if (bb_socket_write(sockfd, buf, read, -1) != read) {
                printf("write error!\n");
                break;
            }
        }
    } else if (flag_send == 2) {
        sockfd = bb_socket_open(hdev, BB_SLOT_0, port, BB_SOCK_FLAG_TX | BB_SOCK_FLAG_RX, NULL);
        if (sockfd < 0) {
            printf("create bb socket failed!\n");
            goto quit;
        }

        pfile = fopen(file, "rb");
        if (!pfile) {
            printf("open file failed!\n");
            goto quit;
        }

        while (1) {
            size_t size = fread(buf, sizeof(char), sizeof(buf), pfile);
            if (size == 0) {
                printf("read finish!\n");
                break;
            }

            if (bb_socket_write(sockfd, buf, size, -1) != size) {
                printf("write error!\n");
                break;
            }

            if (delay) {
                Sleep(delay);
            }
        }
    } else if (flag_send == -2) {
        sockfd = bb_socket_open(hdev, BB_SLOT_0, port, BB_SOCK_FLAG_TX | BB_SOCK_FLAG_RX, NULL);
        if (sockfd < 0) {
            printf("create bb socket failed!\n");
            goto quit;
        }

        pfile = fopen(file, "wb+");
        if (!pfile) {
            printf("open file failed!\n");
            goto quit;
        }

        while (1) {
            int len = bb_socket_read(sockfd, buf, sizeof(buf), -1);
            if (len < 0) {
                printf("read error!\n");
                break;
            }

            size_t size = fwrite(buf, sizeof(char), len, pfile);
            if (size != len) {
                printf("write error!\n");
                break;
            }
        }
    } else {
        sockfd = bb_socket_open(hdev, BB_SLOT_0, port, BB_SOCK_FLAG_TX | BB_SOCK_FLAG_RX, NULL);
        if (sockfd < 0) {
            printf("create bb socket failed!\n");
            goto quit;
        }

        handle = ::CreateNamedPipe(pipe_name, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 1024*1024000, 1024*102400, 0, NULL);
        if (handle == INVALID_HANDLE_VALUE) {
            printf("create pipe failed!\n");
            goto quit;
        }

        if (!::ConnectNamedPipe(handle, NULL)) {
            printf("connect pipe failed!\n");
            goto quit;
        }

        while (1) {
            int read = bb_socket_read(sockfd, buf, sizeof(buf), -1);
            if (read < 0) {
                printf("read error!\n");
                break;
            }

            DWORD write = 0;
            if (!::WriteFile(handle, buf, read, &write, NULL)) {
                printf("write pipe failed!\n");
                break;
            }
        }
    }

quit:
    if (pfile) {
        fclose(pfile);
    }

    if (handle != INVALID_HANDLE_VALUE) {
        CloseHandle(handle);
    }

    if (sockfd < 0) {
        bb_socket_close(sockfd);
    }

    if (handle) {
        bb_dev_close(hdev);
    }

    if (phost) {
        bb_host_disconnect(phost);
    }

    // bb_deinit();

    return 0;
}

